package com.ruoyi;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.ruoyi.app.domain.RelUserMember;
import com.ruoyi.app.dto.Area;
import com.ruoyi.app.mapper.RelUserMemberMapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.DefaultConfig;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.wechat.pay.java.core.cipher.PrivacyEncryptor;
import com.wechat.pay.java.core.http.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import javax.crypto.Cipher;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.stream.Collectors;

/*
@description:
@ClassName RuoYiTestApplication
@author chen
@create 2025-04-02 14:33
@Version 1.0
*/
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class RuoYiTestApplication
{
    @Resource
    @Qualifier("wxPayNoSignClient")
    private CloseableHttpClient wxPayClient;
    @Resource
    RelUserMemberMapper relUserMemberMapper;

    @Resource
    @Qualifier("transferHttpClient")
    private HttpClient httpClient;
    @Resource
    @Qualifier("encryptor")
    private PrivacyEncryptor encryptor;


    @Resource
    @Qualifier
    private BCryptPasswordEncoder passwordEncoder;
    @Test
    public void contextLoads8() throws IOException
    {
        String encode = passwordEncoder.encode("18470479670");
        System.out.println(encode);
    }

    @Test
    public void contextLoads7() throws IOException
    {
        HttpHeaders headers = new HttpHeaders();
        headers.addHeader("Accept", MediaType.APPLICATION_JSON.getValue());
        headers.addHeader("Content-Type", MediaType.APPLICATION_JSON.getValue());
        headers.addHeader("Wechatpay-Serial", encryptor.getWechatpaySerial());

        Map<Object, Object> map = new HashMap<>();
        // 商户AppID
        map.put("appid", Constants.APPLET_APPID);
        // 商户单号
        map.put("out_bill_no", "11111111111111111111111111");
        // 转账场景ID
        map.put("transfer_scene_id", "1000");

        // 收款用户OpenID
        map.put("openid", "oR4Vh7IOsBKXzwmbZLbIxB_KGP6U");

        String userName = "暴振宇";
        if (StringUtils.isNotBlank(userName))
        {
            map.put("user_name", encryptor.encrypt(userName));
        }

        // 转账金额（单位：分）
        map.put("transfer_amount", 1);

        // 转账备注
        map.put("transfer_remark", "提现测试");

        // 回调通知地址
        map.put("notify_url", "https://www.xxx.com/wechat/notify/transferNotify");

        // 用户收款感知
        map.put("user_recv_perception", "现金奖励");

        // 转账场景报备信息
        JSONArray jsonArray = new JSONArray();
        jsonArray.add(new JSONObject().fluentPut("info_type", "活动名称").fluentPut("info_content", "新会员有礼"));
        jsonArray.add(new JSONObject().fluentPut("info_type", "奖励说明").fluentPut("info_content", "注册会员抽奖一等奖"));
        map.put("transfer_scene_report_infos", jsonArray);


        JsonRequestBody build = new JsonRequestBody.Builder()
                .body(JSONUtil.toJsonStr(map))
                .build();

        HttpRequest executeSendGetHttpRequest = new HttpRequest.Builder()
                .httpMethod(HttpMethod.POST)
                .url("https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills")
                .headers(headers)
                .body(build)
                .build();
        try {
            HttpResponse<JSONObject> execute = httpClient.execute(executeSendGetHttpRequest, JSONObject.class);
            JSONObject responseBody = execute.getServiceResponse();
            log.info("发起转账返回：{}", responseBody.toJSONString());
        }  catch (Exception e) {
            e.printStackTrace();
        }
    }


    private String rsaEncryptOAEP(String message) {
        X509Certificate cert = getX509Certificate();
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
            byte[] data = message.getBytes(StandardCharsets.UTF_8);
            byte[] cipherdata = cipher.doFinal(data);
            return Base64.getEncoder().encodeToString(cipherdata);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取 X509Certificate
     */
    private X509Certificate getX509Certificate() {
        ClassLoader classLoader = this.getClass().getClassLoader();
        try (InputStream in = classLoader.getResourceAsStream("v3/platform_cert.pem")) {
            if (in == null) {
                throw new IOException("Resource not found: v3/platform_cert.pem");
            }
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            return (X509Certificate) cf.generateCertificate(in);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }



    @Test
    public void contextLoads6() throws IOException
    {
        String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", Constants.APPLET_APPID, Constants.APPLET_SECRET);
        URL obj = new URL(url);
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();

        // 设置请求属性
        con.setRequestMethod("GET");
        con.setRequestProperty("Content-Type", "application/json");

        int responseCode = con.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_OK)
        { // 200
            BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8));
            String inputLine;
            StringBuilder response = new StringBuilder();

            while ((inputLine = in.readLine()) != null)
            {
                response.append(inputLine);
            }
            in.close();

            System.out.println(response);
            JSONObject jsonObject = JSON.parseObject(response.toString());
            String accessToken = jsonObject.getString("access_token");
            System.out.println(accessToken);

        } else
        {
            System.out.println("66666666");
        }
    }


    @Test
    public void contextLoads5()
    {
        try {
            // 1. 通过类路径获取资源文件
            ClassPathResource resource = new ClassPathResource("templates/regions.json");

            // 2. 创建ObjectMapper实例
            ObjectMapper mapper = new ObjectMapper();

            // 3. 解析JSON到Java对象
            List<Area> areas = mapper.readValue(
                    resource.getInputStream(),
                    mapper.getTypeFactory().constructCollectionType(List.class, Area.class)
            );

            // 4. 格式化输出
            String formattedJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(areas);
            System.out.println(formattedJson);

        } catch (Exception e) {
            System.err.println("读取文件失败，请检查路径和文件名是否正确。错误信息：" + e.getMessage());
        }
    }

    @Test
    public void contextLoads4()
    {
        List<RelUserMember> relUserMembers =
                relUserMemberMapper.selectExpirationList();
        if(null != relUserMembers && relUserMembers.size() >0)
        {
            List<Long> collect = relUserMembers.stream()
                    .map(RelUserMember::getId)
                    .collect(Collectors.toList());
            relUserMemberMapper.expirationList(collect);
        }
    }



    @Test
    public void contextLoads3() throws IOException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
    {
        // 得到价钱（自定义）
        int fee = 1;// 单位是分
        String times = System.currentTimeMillis() + "";

        //订单编号（自定义 这里以时间戳+随机数）
        Random random = new Random();
        String did = times+random.nextInt(1000);

        log.info("生成订单");
        //调用统一下单API
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
        // 请求body参数
        Gson gson = new Gson();
        HashMap<Object, Object> paramsMap = new HashMap<>();
        paramsMap.put("appid",Constants.APPLET_APPID);//appid
        paramsMap.put("mchid",Constants.APPLET_MCH_ID);//商户号
        paramsMap.put("description","商品描述");
        paramsMap.put("out_trade_no",did);//商户订单号
        paramsMap.put("notify_url","http://d4a93w.natappfree.cc/wxBuy");

        //订单金额
        HashMap<Object, Object> amountMap = new HashMap<>();
        amountMap.put("total",fee);//金额
        amountMap.put("currency","CNY");//货币类型
        paramsMap.put("amount",amountMap);

        //支付者
        HashMap<Object, Object> playerMap = new HashMap<>();
        playerMap.put("openid","oR4Vh7IOsBKXzwmbZLbIxB_KGP6U");

        paramsMap.put("payer",playerMap);

        //将参数转化未json字符串
        String jsonParamsMap = gson.toJson(paramsMap);
        log.info("请求参数："+jsonParamsMap);

        StringEntity entity = new StringEntity(jsonParamsMap,"utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        //完成签名并执行请求
        CloseableHttpResponse resp = wxPayClient.execute(httpPost);

        try {
            int statusCode = resp.getStatusLine().getStatusCode();
            String bodyAsString = EntityUtils.toString(resp.getEntity());
            if (statusCode == 200) { //处理成功
                log.info("成功，返回结果 = " + bodyAsString);
            } else if (statusCode == 204) { //处理成功，无返回Body
                log.info("成功");
            } else {
                System.out.println("小程序下单失败,响应码 = " + statusCode + ",返回结果 = " + bodyAsString);
            }
            //相应结果
            HashMap<String,String> resultMap = gson.fromJson(bodyAsString, HashMap.class);


            //获取prepay—id
            String prepayId = resultMap.get("prepay_id");


            //获取到perpayid之后需要对数据进行二次封装，前端调起支付必须存在的参数
            HashMap<String, String> payMap = new HashMap<>();
            payMap.put("appid",Constants.APPLET_APPID);//appid
            long currentTimestamp = System.currentTimeMillis();//时间戳，别管那么多，他就是需要
            payMap.put("timeStamp",currentTimestamp+"");
            String nonceStr = UUID.randomUUID().toString()
                    .replaceAll("-", "")
                    .substring(0, 32);;//随机字符串，别管那么多他就是需要，要咱就给
            payMap.put("nonceStr",nonceStr);
            //apiv3只支持这种加密方式
            payMap.put("signType","RSA");

            payMap.put("package","prepay_id="+prepayId);

            //通过appid，timeStamp，nonceStr，signType，package以及商户密钥进行key=value形式进行拼接加密
            //加密方法我会放在这个代码段段下面
            String aPackage = buildMessageTwo(Constants.APPLET_APPID, currentTimestamp, nonceStr, payMap.get("package"));

            //获取对应的签名
            //加密方法我会放在这个代码段段下面
            String paySign = sign(aPackage.getBytes("utf-8"));

            payMap.put("paySign",paySign);

            log.info("给前端的玩意："+payMap);//前端会根据这些参数调起支付页面

        }finally {
            resp.close();
        }


    }


    public  String sign(byte[] message) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        Signature sign = Signature.getInstance("SHA256withRSA"); //SHA256withRSA
        InputStream inputStream = DefaultConfig.class.getClassLoader().getResourceAsStream("client/apiclient_key.pem");
        sign.initSign(PemUtil.loadPrivateKey(inputStream)); // 微信证书私钥
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }




    public  String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag)
    {
        return appId + "\n" + timestamp + "\n" + nonceStr + "\n" + packag + "\n";
    }

}
